package com.wimcorp.magic.abilities;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Table;

import com.wimcorp.magic.abilities.trigger.AbilityTrigger;
import com.wimcorp.magic.board.CardAccessor;
import com.wimcorp.magic.board.PlayingDeck;
import com.wimcorp.magic.cards.Artifact;
import com.wimcorp.magic.cards.Creature;
import com.wimcorp.magic.cards.Enchantment;
import com.wimcorp.magic.cards.Instant;
import com.wimcorp.magic.cards.Land;
import com.wimcorp.magic.cards.Permanent;
import com.wimcorp.magic.cards.Planeswalker;
import com.wimcorp.magic.cards.PlayingCard;
import com.wimcorp.magic.cards.Sorcery;
import com.wimcorp.magic.color.Color;
import com.wimcorp.magic.exception.CastException;
import com.wimcorp.magic.input.Location;
import com.wimcorp.magic.input.Type;

/**
 * example {keep_destination : HAND,return_destination : BOTTOM_DECK, type :
 * ISLAND, amount : 3}
 * 
 * type : ISLAND,CREATURE,...
 * 
 * keep_destination : HAND
 * 
 * return_destination : BOTTOM_DECK
 * 
 * amount : 3
 */
@Entity
@Table(name = "revealdeckkeeptypeandreturninanyorder", schema = "abilities")
public class RevealDeckKeepTypeAndReturnInAnyOrder extends Ability {

	private int amount;

	@Enumerated(EnumType.STRING)
	private Location keepDestination;

	@Enumerated(EnumType.STRING)
	private Location returnDestination;

	public RevealDeckKeepTypeAndReturnInAnyOrder() {

	}

	public RevealDeckKeepTypeAndReturnInAnyOrder(AbilityTrigger trigger) {
		super(trigger);
	}

	public RevealDeckKeepTypeAndReturnInAnyOrder(RevealDeckKeepTypeAndReturnInAnyOrder ability) {
		super(ability);
		this.keepDestination = ability.getKeepDestination();
		this.returnDestination = ability.getReturnDestination();
		this.amount = ability.getAmount();
	}

	public void cast() throws Exception {
		PlayingDeck deck = getPlayer().getDeck();
		getPlayer().getUserInterface().message(getDescription());

		long[] returnOptions = new long[amount];
		List<PlayingCard> keepCards = new ArrayList<>();
		List<PlayingCard> returnCards = new ArrayList<>();
		for (int i = 0; i < amount; i++) {
			returnCards.add(deck.getTopCard());
		}

		// split cards in 2 piles
		// one keep and one return pile. The return pile will be ordered by the
		// user

		for (int i = 0; i < amount; i++) {
			PlayingCard card = returnCards.get(i);
			getPlayer().getUserInterface().message(card.toString());
			if (getTypes().contains(card.getType().toUpperCase())) {
				keepCards.add(card);
			} else {
				returnOptions[i] = card.getIdentifier();
			}
		}

		for (PlayingCard card : keepCards) {
			moveCard(card, keepDestination);
		}

		amount = amount - keepCards.size();

		Long[] result = getPlayer().getUserInterface().order("Order cards : ", returnOptions);
		PlayingCard[] returnOrder = new PlayingCard[amount];
		for (PlayingCard card : returnCards) {
			for (int i = 0; i < returnOrder.length; i++) {
				if (card.getIdentifier() == result[i]) {
					returnOrder[i] = card;
					break;
				}
			}
		}
		for (int i = amount - 1; i > returnOrder.length; i--) {
			moveCard(returnOrder[i], returnDestination);
			getPlayer().getDeck().addOnTop(returnOrder[i]);
		}

	}

	private void moveCard(PlayingCard card, Location location) {
		switch (location) {
		case BOTTOM_DECK:
			card.unsummon();
			getPlayer().getDeck().addOnBottom(card);
			break;
		case EXILE:
			card.exile();
			break;
		case GRAVEYARD:
			card.graveyard();
			break;
		case HAND:
			card.unsummon();
			getPlayer().getHand().add(card);
			break;
		case TOP_DECK:
			card.unsummon();
			getPlayer().getDeck().addOnTop(card);
			break;
		}
	}



	@Override
	protected void executeAbility() throws CastException {

	}

	public int getAmount() {
		return amount;
	}

	public Location getKeepDestination() {
		return keepDestination;
	}

	public Location getReturnDestination() {
		return returnDestination;
	}

	@Override
	public RevealDeckKeepTypeAndReturnInAnyOrder clone() {
		return new RevealDeckKeepTypeAndReturnInAnyOrder(this);
	}

	public void setAmount(int amount) {
		this.amount = amount;
	}

	public void setKeepDestination(Location keepDestination) {
		this.keepDestination = keepDestination;
	}

	public void setReturnDestination(Location returnDestination) {
		this.returnDestination = returnDestination;
	}
	
	
	

}
